package cn.uway.utils;

 
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.SocketTimeoutException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ConnectionPoolTimeoutException;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class HttpUtils {

	//web 应用的接口秘钥
	private static final String appId="67d307e4d1d143d6acd6a33a87d367b9";
	private static final String secretKey="55f2bfde6cd64f00acd2294bbd0963f4";

		
	private static Logger logger = LoggerFactory.getLogger(HttpUtils.class);

    //连接超时时间，默认30秒
    private static int connectTimeout = 30*1000;
    
    //数据传输超时时间，默认30秒
    private static int socketTimeout = 30*1000;
    
    /**
     * 
     * @param url 纯url, 不包含?和&符号的参数
     * @param param 不带?, 格式形如: key1=value1&key2=value2&key3=value3
     * 特别说明，如果参数值带有富文本编辑的HTML转义字符，则请不要使用此方法，建议换用传parameterMap的方法
     * @return
     */
    public static String sendPost(String url, String param){
    	CloseableHttpClient httpClient = HttpClients.custom().build();
   	    logger.debug("=================【http请求】url={},param={}", url, param);
  	    HttpPost httpPost = new HttpPost(url);
  	     //设置请求器的配置
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).build();          
        httpPost.setConfig(requestConfig);
        String result = "";
        String fullUrl = url;	 
        try {   
        	if(param!=null && !"".equals(param.trim())){
     	    	fullUrl = url+"?"+param;	
     	    	HttpEntity strEntity = new StringEntity(param,"UTF-8");
            	httpPost.setEntity(strEntity);
     	    }        	
            HttpResponse response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            if(entity!=null){
	        	if(response.getStatusLine().getStatusCode()==200){
	        		result = EntityUtils.toString(entity, "UTF-8");
	        	}
	        	else{
	        		logger.warn("http状态码异常,HTTP StatusCode={}", response.getStatusLine().getStatusCode());	
			    }
	        }            
        } catch (ConnectionPoolTimeoutException e) {
             logger.error("http连接超时,url"+fullUrl, e);
        } catch (ConnectTimeoutException e) {
      	      logger.error("http连接超时,url="+fullUrl, e);
        } catch (SocketTimeoutException e) {
      	     logger.error("http读取数据超时,url="+fullUrl, e);
        } catch (Exception e) {
      	     logger.error("http请求其它错误,url="+fullUrl, e);
        } 
        finally {
      	    if(httpClient!=null){
      		      try {	 httpClient.close();  } catch ( IOException e ) {	}
      	    }        	  
        }
        logger.debug("=================【http返回】result={}", result);
        return result;
    }
    
    /**
     * 
     * @param url 纯url, 不包含?和&符号的参数
     * @param param 不带?, 格式形如: key1=value1&key2=value2&key3=value3
     * 特别说明，如果参数值带有富文本编辑的HTML转义字符，则请不要使用此方法，建议换用传parameterMap的方法
     * @return
     */
    public static String sendGet(String url, String param){
    	CloseableHttpClient httpClient = HttpClients.custom().build();
   	    logger.debug("=================【http请求】url={},param={}", url, param);
   	    String fullUrl = url;
   	    if(param!=null && !"".equals(param.trim())){
	    	fullUrl = url+"?"+param;	
	    } 
  	    HttpGet httpGet = new HttpGet(fullUrl);
  	    //设置请求器的配置
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).build();          
        httpGet.setConfig(requestConfig);
        String result = "";
        try {       	 
            HttpResponse response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            if(entity!=null){
	        	if(response.getStatusLine().getStatusCode()==200){
	        		result = EntityUtils.toString(entity, "UTF-8");
	        	}
	        	else{
	        		logger.warn("http状态码异常,HTTP StatusCode={}", response.getStatusLine().getStatusCode());	
			    }
	        }              
        } catch (ConnectionPoolTimeoutException e) {
             logger.error("http连接超时,url"+fullUrl, e);
        } catch (ConnectTimeoutException e) {
      	      logger.error("http连接超时,url="+fullUrl, e);
        } catch (SocketTimeoutException e) {
      	     logger.error("http读取数据超时,url="+fullUrl, e);
        } catch (Exception e) {
      	     logger.error("http请求其它错误,url="+fullUrl, e);
        } 
        finally {
      	    if(httpClient!=null){
      		      try {	 httpClient.close();  } catch ( IOException e ) {	}
      	    }        	  
        }
        logger.debug("=================【http返回】result={}", result);
        return result;
    }
    
    
    /**
     * 
     * @param url 纯url, 不包含?和&符号的参数
     * @param parameterMap 装有参数键值对的Map
     * 本方法支持富文本（HTML转义字符内容） 
     * @return
     */
    public static String sendPost(String url, Map<String, String> parameterMap){
    	CloseableHttpClient httpClient = HttpClients.custom().build();
   	    logger.debug("=================【http请求】url={}, parameterMap={}", url, parameterMap);
  	    HttpPost httpPost = new HttpPost(url);
  	     //设置请求器的配置
  	    RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).build();          
        httpPost.setConfig(requestConfig);
        String result = "";
        try {  
	      	List<BasicNameValuePair> parameterList = new ArrayList<BasicNameValuePair>();
	      	Set<Entry<String,String>> entrySet = parameterMap.entrySet();
	      	for(Iterator<Entry<String,String>> it = entrySet.iterator(); it.hasNext(); ){
	      		Entry<String,String> entry = it.next();
	      		parameterList.add( new BasicNameValuePair(entry.getKey(), entry.getValue() ) );
	      	}        	
	      	HttpEntity formEntity = new UrlEncodedFormEntity(parameterList, "UTF-8");
	      	httpPost.setEntity(formEntity);
	        HttpResponse response = httpClient.execute(httpPost);
	        HttpEntity entity = response.getEntity();
	        if(entity!=null){
	        	if(response.getStatusLine().getStatusCode()==200){
	        		result = EntityUtils.toString(entity, "UTF-8");
	        	}
	        	else{
	        		logger.warn("http状态码异常,HTTP StatusCode={}", response.getStatusLine().getStatusCode());	
			    }
	        }             
	     } catch (ConnectionPoolTimeoutException e) {
	           logger.error("http连接超时,url="+url,e);
	     } catch (ConnectTimeoutException e) {
	    	      logger.error("http连接超时,url="+url,e);
	     } catch (SocketTimeoutException e) {
	    	     logger.error("http读取数据超时,url="+url,e);
	     } catch (Exception e) {
	    	     logger.error("http请求其它错误,url="+url,e);
	     } 
	     finally {
	    	    if(httpClient!=null){
	    		      try {	 httpClient.close();  } catch ( IOException e ) {	}
	    	    }        	  
	     }
	     logger.debug("=================【http返回】result={}", result);
	     return result;
    }
        
    /**
     * 发送post请求，并生成数字签名验证所需要的参数
     * @param url
     * @param param 不带?, 格式形如: key1=value1&key2=value2&key3=value3
     * 特别说明，如果参数值带有富文本编辑的HTML转义字符，则请不要使用此方法，建议换用传parameterMap的方法
     * @return
     */
    public static String sendPostWithSignature(String url, String param) {
    	if(param==null){
			param = "";
		}
		if(!param.contains("appId=")){
			if("".equals(param.trim())){
				param = "appId="+appId;
			}
			else{
				param += "&appId="+appId;
			}			
		}
		
		/*
		String param1 = param;
		try {
			param1 = URLDecoder.decode(param, "utf-8");  //如果param中的中文参数带%AB%DE之类的编码，需要还原成中文，再利用中文计算sign
		} 
		catch (UnsupportedEncodingException e ) {
			e.printStackTrace();		    
		}	
		
		String sign = getSignString(param1);
		param += "&sign="+sign;
		logger.debug("===============sign="+sign);
		*/
		
		Map<String,String>  paramMap = getParameterMap(param);		
		
		return sendPostWithSignature( url,  paramMap);
    }
    
    /**
     * 发送post请求，并生成数字签名验证所需要的参数
     * @param url 纯url, 不包含?和&符号的参数
     * @param parameterMap 装有参数键值对的Map
     * 本方法支持富文本（HTML转义字符内容） 
     * @return
     */    
    public static String sendPostWithSignature(String url, Map<String,String> paramMap) {
    	if(!paramMap.containsKey("appId")){
			paramMap.put("appId", appId);		
		}
		String sign = getSignString(paramMap);
		paramMap.put("sign", sign);	
		logger.debug("===============sign="+sign);
		
		return sendPost(url,  paramMap);
    }
    
    public static  String  getSignString(String parameterString){
		if(parameterString.startsWith("?")){
			parameterString = parameterString.substring(1); //去掉开头的问号
		}
		String[] params = parameterString.split("&");
		Map<String, String> paramTreeMap = new TreeMap<String, String>();
		for(String parameter : params){
			int pos = parameter.indexOf("=");
			String key = parameter.substring(0,pos);
			String val = parameter.substring(pos+1);
			if(key!=null && !"".endsWith(key.trim()) && !"sign".equals(key)){
				if(val!=null && !"".equals(val.trim())){
					paramTreeMap.put(key, val);
				}	
			}
		}
		
		StringBuilder sb = new StringBuilder();
    	Iterator<String> iter = paramTreeMap.keySet().iterator();
		while (iter.hasNext()) {
			String name = (String) iter.next();
			sb.append(name).append(paramTreeMap.get(name));
		}
		sb.append(secretKey);
		return MD5Encoder.encode(sb.toString());
	}	
    
    
    public static  Map<String,String>   getParameterMap(String parameterString){
		if(parameterString.startsWith("?")){
			parameterString = parameterString.substring(1); //去掉开头的问号
		}
		String[] params = parameterString.split("&");
		Map<String, String> paramMap = new HashMap<String, String>();
		for(String parameter : params){
			int pos = parameter.indexOf("=");
			String key = parameter.substring(0,pos);
			String val = parameter.substring(pos+1);
			paramMap.put(key, val);
		}
		return paramMap;
	}	
	
    
    public static  String  getSignString(Map<String,String> paramMap){
		Map<String, String> paramTreeMap = new TreeMap<String, String>();
		paramTreeMap.putAll(paramMap); //使用treeMap对参数进行排序
		StringBuilder sb = new StringBuilder();
    	Iterator<String> it = paramTreeMap.keySet().iterator();
    	try{
    		while (it.hasNext()) {
    			String key = it.next();
    			String val = paramTreeMap.get(key);
    			
    			System.out.println("==============="+key+":"+val);
    			
    			if(key!=null && !"".endsWith(key.trim()) && !"sign".equals(key)){
    				if(val!=null && !"".equals(val.trim())){
    					//计算sign的时候，需要使用中文，如果传入的中文参数被编码成了%AB%DE%2F,则需要decode还原
    					sb.append(key).append( URLDecoder.decode(val, "utf-8") );  
    				}	
    			}			
    		}
    	}
    	catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		sb.append(secretKey);
		return MD5Encoder.encode(sb.toString());
	}	
    
    
    public static void main(String[] args){
	  /*
    	String param ="projectId=50281f58cc2b403e90fbe5835a3b5407&districtId=&province=&city=&arearegion=&lonlat=222&type=&photoPath=/home/upload/50281f58cc2b403e90fbe5835a3b5407/50281f58cc2b403e90fbe5835a3b5407&loginId=941589ab53f443dc88b204ad1510ac1d";

    	param= param+"&projectName=中文"; 
		param= param+"&status=中文乱码" ; 
    	
	    
    	System.out.println(param);
    	String result  = HttpUtils.sendPostWithSignature("http://10.42.20.215:8080/truemonitor/system/project/update", 
	        		param);		

	    System.out.println(result);
	    
	    */
    	
    }
    
    
}
